Object Oriented Programming
(compared to Functional programming)
Python is "object oriented" like C++ and Java.
But what does this mean?
First, understand "procedural programming" as found other languages
like C and shell scripts.
Yet to explain that, let's begin with something in which everyone already is
familiar: entering commands from a prompt.
(Windows and DOS call it the command prompt; Unix calls it the shell.)
Issue a straight-forward command such as DIR to get a directory listing.
C:\>dir
Volume in drive C has no label.
Volume Serial Number is C829-8FDE
Directory of C:\
03/04/2004 10:49 AM
cygwin
02/24/2004 03:10 PM Documents and Settings
07/23/2003 06:59 AM downloads
03/02/2004 03:01 PM emacs
03/04/2004 02:49 PM emacs-test
03/16/2004 07:57 AM home
02/24/2004 02:01 PM Program Files
03/02/2004 09:55 AM Python23
02/24/2004 01:50 PM Temp
03/15/2004 01:03 PM tmp
02/24/2004 04:04 PM WINDOWS
10/29/2002 06:35 AM WXPFILES
06/03/2002 12:00 PM 34 AUTOEXEC.BAT
10/29/2002 06:05 AM 151 liprefs.js
2 File(s) 185 bytes
12 Dir(s) 34,358,518,272 bytes free
You named a function (i.e., the DIR command) and received a result. For
this particular function, you received the default-- long listing of files
with details such as modification dates.
Now, provide a command-line switch to get columns: /w
C:\>dir /w
Volume in drive C has no label.
Volume Serial Number is C829-8FDE
Directory of C:\
[cygwin] [Documents and Settings] [drv]
[emacs] [emacs-test] [home]
[Program Files] [Python23] [tmp]
[WINDOWS] [WUTemp] [WXPFILES]
AUTOEXEC.BAT liprefs.js
2 File(s) 185 bytes
12 Dir(s) 34,358,518,272 bytes free
In terms of procedural programming, the "w" would be the "parameter."
Understand that when you provided the slash (/) preceding the letter (w),
it's just syntax, grammar.
Next, call the same function (using that term loosely), but with a different
parameter. Use /b for a basic list without multiple columns or time (but
you might wish to avoid /s as that recursively lists all subdirectories).
C:\>dir /b
cygwin
Documents and Settings
drv
emacs
emacs-test
home
Program Files
Python23
tmp
WINDOWS
WUTemp
WXPFILES
AUTOEXEC.BAT
liprefs.js
So, the function and syntax remain the same, but the parameter changed.
In procedural programming, it would look more like this:
def dir(switch):
if switch is None:
os.system("dir")
else:
os.system("dir /" + switch)
dir("w") # new notation, compared to: dir /w
dir("b")
We've changed the syntax that you use directly but preserved the name
and parameters. It's still called "dir" and you can still use the same
parameters as from the command prompt examples.
(For brevity, output is omitted from those calls to "dir" function as they
would be identical to the command prompt examples shown earlier.)
Note: to actually make the above function work within the Python
interpretor, you must import the "os" module before running your code:
import os
To make something Object Oriented is basically just a change in syntax.
Continuing our example, we merely *add* to the previous code.
class DirectoryListing:
def dir(self, switch): # added "self" parameter
if switch is None:
os.system("dir")
else:
os.system("dir /" + switch)
dl = DirectoryListing() # additional step: calling the "constructor"
dl.dir("w")
dl.dir("b")
In terms of program logic everything you can do within an object oriented
framework has an equivalent in procedural programming.
Object oriented programming adds value as complexity of your code increases.
The real benefit comes when people read the source code. (This becomes
evident with further exposure.)
Think of an "object" as much like an envelope: it contains data and
functions (the correct term is "methods" actually) so that you have a single
bundle in which to handle.
As with a letter sent through the post office, it contains data (your
letter, stamp, destination address, return address, postal stamp) and has
methods.
The *method* of delivery depends upon (or "is a function of") the postage
affixed to the envelope. Basic postage means 3-5 business days for
delivery, whereas different postage might offer overnight delivery.
Yet at any of the postal transfer facilities, they always know where that
individual letter is going because all data necessary for delivery is
contained on the envelope.
So just think of the data within an object being contained *in* rather than
*on* its envelope.
But wait, there's more... Inheritance.
Inheritence simplifies your program by creating "base classes" from which to
expand upon elsewhere.
class PostalEnvelope:
destinationAddress = None
returnAddress = None
postageClass = None
data = None
def Delivery(self):
if self.postageClass == "A":
print "Standard"
elif self.postageClass == "Express":
print "Rush / Overnight"
elif self.postageClass == "bulk":
print "It gets there whenever it gets there"
class Letter (PostalEnvelope):
returnAddress = "1 Pike Place, Seattle, WA 98101"
destinationAddress = "1000 Dexter Ave N, Seattle, WA 98109"
postageClass = "A"
data = "Pike Place Market is a nice place for lunch"
memo = Letter()
memo.Delivery() # yet .Delivery() was defined elsewhere.
"Standard"
The "memo" object gets passed *implicitly* to Delivery() as the value of
"self". The Python framework does this for you, transparently.
Calling the constructor (which also happens implicitly) is in effect
assigning a reference to the location in memory where the object has been
created.
So then, an "object" is really just a variable like with any other simple
language but implies *how* it gets used. (For example, you wouldn't treat
this data as if it were just an integer; likewise, you wouldn't treat an
integer like a string.)
References to "self" are just a way to track data associated with the
envelope.
This is functionally equivalent to the previous chunk of code:
memo = Letter()
##memo.Delivery()
Letter.Delivery(memo) # Strange but illustrates how "self" gets assigned
"Standard"
This time, the "memo" object gets passed *explicitly* to Delivery().
It works, but you won't see this technique used much in common code (but is
used, however, for languages like C and Lisp).